package org.jeecg.common.util.oss;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.constant.SymbolConstant;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.filter.SsrfFileTypeFilter;
import org.jeecg.common.util.filter.StrAttackFilter;
import org.jeecg.config.oss.ZosConfiguration;
import org.jetbrains.annotations.NotNull;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

/**
 * 天翼云 zos 上传工具类
 */
@Slf4j
public class ZosBootUtil {

    private static ZosConfiguration zosConfiguration;
    private static AmazonS3 s3Client;

    public static void init(ZosConfiguration zosConfiguration) {
        ZosBootUtil.zosConfiguration = zosConfiguration;
        AWSCredentials credentials = new BasicAWSCredentials(zosConfiguration.getAccessKey(), zosConfiguration.getSecretKey());
        ClientConfiguration awsClientConfig = new ClientConfiguration();
        // 设置请求签名格式：
        //"S3SignerType"，V2签名；
        //"AWSS3V4SignerType"，V4签名。
        awsClientConfig.setSignerOverride("AWSS3V4SignerType");
        awsClientConfig.setProtocol(Protocol.HTTP);
        ZosBootUtil.s3Client = AmazonS3ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withClientConfiguration(awsClientConfig)
                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(zosConfiguration.getEndpoint(), "")) // 设置终端节点
                .disableChunkedEncoding()
                .enablePathStyleAccess()
                .build();
    }

    /**
     * 上传文件
     * 文件上传成功,返回文件完整访问路径
     * 文件上传失败,返回 null
     *
     * @param file    待上传文件
     * @param fileDir 文件保存目录
     * @return oss 中的相对文件路径
     */
    public static String upload(MultipartFile file, String fileDir,String customBucket) throws Exception {
        SsrfFileTypeFilter.checkUploadFileType(file);
        StringBuilder fileUrl = new StringBuilder();
        String bucket = StringUtils.defaultIfBlank(customBucket, zosConfiguration.getBucketName());
        try {
            //判断桶是否存在,不存在则创建桶
            HeadBucketResult result = s3Client.headBucket(new HeadBucketRequest(bucket));
            if(StringUtils.isEmpty(result.getBucketRegion())){
                s3Client.createBucket(new CreateBucketRequest(bucket));
            }
            // 获取文件名
            String fileName = StringUtils.defaultIfBlank(file.getOriginalFilename(), file.getName());
            fileName = CommonUtils.getFileName(fileName);
            fileName = !fileName.contains(".")
                              ? fileName + "_" + System.currentTimeMillis()
                              : StringUtils.substringBeforeLast(fileName, ".") + "_" + System.currentTimeMillis() + "." + StringUtils.substringAfterLast(fileName, ".");
            if (!fileDir.endsWith(SymbolConstant.SINGLE_SLASH)) {
                fileDir = fileDir.concat(SymbolConstant.SINGLE_SLASH);
            }
            //u  过滤上传文件夹名特殊字符，防止攻击
            fileDir= StrAttackFilter.filter(fileDir);
            fileUrl.append(fileDir).append(fileName);
            String filePath = String.format("https://%s/%s/%s", zosConfiguration.getEndpoint(), bucket, fileUrl);
            PutObjectRequest request = new PutObjectRequest(bucket, fileUrl.toString(), file.getInputStream(), new ObjectMetadata());
            PutObjectResult putResult = s3Client.putObject(request);
            // 设置可读
            SetObjectAclRequest req = new SetObjectAclRequest(zosConfiguration.getBucketName(), fileUrl.toString(), CannedAccessControlList.PublicRead);
            s3Client.setObjectAcl(req);
            if (putResult != null) {
                log.info("------Zos文件上传成功------ {}", filePath);
            }
            return filePath;
        } catch (Exception e) {
            log.error("Zos文件上传失败", e);
            return null;
        }
    }

    public static String upload(InputStream stream, String relativePath) {
        String filePath = String.format("https://%s/%s/%s", zosConfiguration.getEndpoint(), zosConfiguration.getBucketName(), relativePath);
        PutObjectRequest request = new PutObjectRequest(zosConfiguration.getBucketName(), relativePath, stream, new ObjectMetadata());
        s3Client.putObject(request);
        // 设置可读
        SetObjectAclRequest req = new SetObjectAclRequest(zosConfiguration.getBucketName(), relativePath, CannedAccessControlList.PublicRead);
        s3Client.setObjectAcl(req);
        return filePath;
    }

    public static String upload(File file, String relativePath) {
        String filePath = String.format("https://%s/%s/%s", zosConfiguration.getEndpoint(), zosConfiguration.getBucketName(), relativePath);
        PutObjectRequest request = new PutObjectRequest(zosConfiguration.getBucketName(), relativePath, file);
        s3Client.putObject(request);
        // 设置可读
        SetObjectAclRequest req = new SetObjectAclRequest(zosConfiguration.getBucketName(), relativePath, CannedAccessControlList.PublicRead);
        s3Client.setObjectAcl(req);
        return filePath;
    }

    public static String upload(MultipartFile file, String fileDir) throws Exception {
        return upload(file, fileDir,null);
    }
    public static String upload(FileItemStream file, String fileDir) throws Exception {
        return upload(new MultipartFile() {
            @NotNull
            @Override
            public String getName() {
                return file.getName();
            }

            @Override
            public String getOriginalFilename() {
                return file.getName();
            }

            @Override
            public String getContentType() {
                return file.getContentType();
            }

            @Override
            public boolean isEmpty() {
                return false;
            }

            @Override
            public long getSize() {
                throw new RuntimeException("不支持的操作");
            }

            @NotNull
            @Override
            public byte[] getBytes() throws IOException {
                throw new RuntimeException("不支持的操作");
            }

            @NotNull
            @Override
            public InputStream getInputStream() throws IOException {
                return file.openStream();
            }

            @Override
            public void transferTo(@NotNull File dest) throws IOException, IllegalStateException {
                throw new RuntimeException("不支持的操作");
            }
        }, fileDir);
    }

    /**
     * 删除文件
     */
    public static void delete(String fileName, String customBucket) {
        String bucket = StringUtils.defaultIfBlank(customBucket, zosConfiguration.getBucketName());
        s3Client.deleteObject(new DeleteObjectRequest(bucket, fileName));
    }

    /**
     * 删除文件
     */
    public static void delete(String fileName) {
        delete(fileName, null);
    }

}